﻿using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Ynzp.Core.AspNet;
using Ynzp.Core.Exceptions;
using Exceptionless;
using System.Linq;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Mvc.Formatters;
using System.IO;
using ExceptionlessDemo.Filter;
using Exceptionless.Plugins;

namespace SerilogDemo.Filter
{
    /// <summary>
    /// 全局异常错误过滤
    /// </summary>
    public class GlobalExceptionFilter : IExceptionFilter
    {
        private readonly IWebHostEnvironment _env;
        private readonly ILogger<GlobalExceptionFilter> _logger;

        public GlobalExceptionFilter(IWebHostEnvironment env, ILogger<GlobalExceptionFilter> logger)
        {
            _env = env;
            _logger = logger;
        }

        public void OnException(ExceptionContext context)
        {
            int code;
            string message;
            BizException bizException = null;
            Exception exception = context.Exception;
            //判断是不是BizException
            if (exception is BizException)
            {
                bizException = (BizException)exception;
            }
            else if (exception.InnerException is BizException)
            {
                bizException = (BizException)exception.InnerException;
            }
            //设置Code和Message,生产环境和非生产环境不同
            if (_env.IsProduction())
            {
                if (bizException != null)
                {
                    code = bizException.ErrCode;
                    message = bizException.ShowMsg;
                }
                else
                {
                    code = ResultCodes.Status500InternalServerError.ToInt32();
                    message = exception.Message;
                }
            }
            else
            {
                if (bizException != null)
                {
                    code = bizException.ErrCode;
                    message = bizException.Message;
                }
                else
                {
                    code = ResultCodes.Status500InternalServerError.ToInt32();
                    message = exception.Message;
                }
            }

            //返回客户端的数据
            var data = ApiResult.NotOk(code, message);
            context.Result = new ObjectResult(data)
            {
                StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError
            };

            //异步记录日志
            WriteRequestToLogAsync(context);//.ConfigureAwait(false); 
        }

        /// <summary>
        /// 异步记录日志
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private async Task WriteRequestToLogAsync(ExceptionContext context)
        {
            SortedDictionary<string, object> _data = new SortedDictionary<string, object>();

            //获得请求头
            HttpRequest request = context.HttpContext.Request;
            _data.Add("Url", request.Path.ToString());
            _data.Add("Headers", request.Headers.ToDictionary(x => x.Key, v => string.Join(";", v.Value.ToList())));
            _data.Add("Method", request.Method);
            //_data.Add("request.executeStartTime", DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));

            //获取请求body内容
            var body = await HttpRequestHelper.ReadBodyAsync(request);
            _data.Add("Body", body);

            

            //提交到Exceptionless
/*            var contextData = new ContextData();
            contextData.MarkAsUnhandledError();
            contextData.SetSubmissionMethod(nameof(GlobalExceptionFilter));*/
            context.Exception
               .ToExceptionless()
               // 设置一个ReferenceId方便查找
               .SetReferenceId(Guid.NewGuid().ToString("N"))
               //Exceptionless自动从请求中提取请求Body,但是没有提取所有请求头信息
               //.SetHttpContext(context.HttpContext)
               //手动获取请求头和请求Body数据，并放入提交对象中
               .SetProperty("请求详情", _data)
               .Submit();
            
            //记录日志
            _logger.LogError(context.Exception,"");
        }


    }

}


